package com.rskj.cashbook.service.iml;

import com.rskj.cashbook.dao.UserInfoDao;
import com.rskj.cashbook.iexception.BusinessException;
import com.rskj.cashbook.response.ResponseEntity;
import com.rskj.cashbook.service.IUserInfoService;
import com.rskj.cashbook.util.JwtUtil;
import com.rskj.cashbook.util.RedisUtil;
import com.rskj.cashbook.util.SnowflakeIdWorker;
import com.rskj.cashbook.vo.UserInfo;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collections;


@Service
@AllArgsConstructor
@Slf4j
@Transactional
public class UserInfoService implements IUserInfoService {


    private final PasswordEncoder passwordEncoder;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private JwtUtil jwtUtil;

    @Resource
    private UserInfoDao userInfoDao;
    private final AuthenticationManager authenticationManager;

    @Override
    public UserInfo getUserInfo(UserInfo userInfo) {
        try {
            UsernamePasswordAuthenticationToken authenticationToken =
                    new UsernamePasswordAuthenticationToken(userInfo.getAccount(), userInfo.getPassword());
            Authentication authentication = authenticationManager.authenticate(authenticationToken);
            if (authentication.isAuthenticated()) {
                SecurityContextHolder.getContext().setAuthentication(authentication);
                return userInfoDao.getUserInfo(userInfo).setPassword(null);
            }
        } catch (BadCredentialsException e) {
            throw new BusinessException(e.getMessage());
        }

        return null;
    }

    /**
     * 注册用户
     *
     * @param userInfo 用户信息
     * @return 注册结果
     */
    @Override
    public UserInfo addUserInfo(UserInfo userInfo) {
        if (StringUtils.isBlank(userInfo.getAccount()) || StringUtils.isBlank(userInfo.getPassword())) {
            throw new BusinessException("账户密码不能为空");
        }
        UserInfo insertTemp = (UserInfo) new UserInfo()
                .setUserName(userInfo.getUserName())
                .setAccount(userInfo.getAccount())
                .setPassword(passwordEncoder.encode(userInfo.getPassword()))
                .setId(SnowflakeIdWorker.getId());
        UserInfo dbUser = userInfoDao.getUserInfo(new UserInfo().setAccount(userInfo.getAccount()));
        if (dbUser != null) {
            throw new BusinessException("账户已存在");
        }
        userInfoDao.save(insertTemp);
        return insertTemp.setPassword("***");
    }

    @Override
    public String getCurrUsername() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            throw new BusinessException("用户未登录");
        }
        if (authentication.getPrincipal() instanceof UserDetails) {
            return ((UserDetails) authentication.getPrincipal()).getUsername();
        }
        return authentication.getPrincipal().toString();
    }

    /**
     * 退出登录
     *
     * @param request  请求
     * @param response 响应
     * @return 退出登录结果
     */
    public ResponseEntity<Object> logout(HttpServletRequest request, HttpServletResponse response) {
        try {
            String token = request.getHeader("Authorization");
            if (StringUtils.isNotBlank(token) && token.startsWith("Bearer ")) {
                token = token.substring(7);

                // 从token中提取用户名和设备ID
                String username = jwtUtil.extractUsername(token);
                String deviceId = jwtUtil.extractDeviceId(token);

                if (StringUtils.isNotBlank(username) && StringUtils.isNotBlank(deviceId)) {
                    // 删除特定设备的token
                    jwtUtil.logoutDevice(username, deviceId);
                    log.info("User {} logged out from device: {}", username, deviceId);
                }
            }

            // 清理安全上下文
            SecurityContextHolder.clearContext();
            request.getSession().invalidate();

            // 清理Cookie
            Cookie cookie = new Cookie("JSESSIONID", null);
            cookie.setPath("/");
            cookie.setHttpOnly(true);
            cookie.setMaxAge(0);
            response.addCookie(cookie);

            return ResponseEntity.ok("退出成功");
        } catch (Exception e) {
            log.error("Error during logout: {}", e.getMessage(), e);
            return ResponseEntity.failGeneric("退出失败: " + e.getMessage());
        }
    }

    /**
     * 修改密码
     *
     * @param userInfo 用户信息
     * @return 修改密码结果
     */
    public ResponseEntity<Object> updatePassword(UserInfo userInfo) {
        UserInfo user = userInfoDao.getUserInfo(userInfo);
        if (null == user) {
            throw new BusinessException("用户不存在");
        }
        // 密码长度不能小于6
        if (user.getPassword().length() < 6) {
            throw new BusinessException("密码长度不能小于6");
        }
        // 比较新旧密码是否一致
        if (user.getPassword().equals(userInfo.getPassword())) {
            throw new BusinessException("新密码不能与旧密码一致");
        }
        // 修改密码
        user.setPassword(passwordEncoder.encode(userInfo.getPassword()));

        int row = userInfoDao.update(user);
        if (row > 0) {
            return ResponseEntity.ok("修改密码成功");
        }

        throw new BusinessException("修改密码失败，请联稍后再试");
    }


}
